package ac.il.technion.c236369.hw4.core.protocol;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.entity.FileEntity;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import ac.il.technion.c236369.hw4.configuration.ServerConfig;
import ac.il.technion.c236369.hw4.core.entity.EntityTemplate;
import ac.il.technion.c236369.hw4.core.producers.AccessDeniedContentProducer;
import ac.il.technion.c236369.hw4.core.producers.FileNotFoundContenProducer;
import ac.il.technion.c236369.hw4.core.producers.UnsupportedFileExtension;

/**
 * @author Artem Barger, Maxim Aizenshtein
 * 
 * Class which has to handle request for files with extensions for
 * there is no type handler defined.
 */
public class DefaultRequestHandler implements HttpRequestHandler {

	private Logger log = Logger.getLogger( DefaultRequestHandler.class);
	@Override
	public void handle(final HttpRequest request, HttpResponse response, HttpContext context)
			throws HttpException, IOException {
        String method = request.getRequestLine().getMethod().toUpperCase( Locale.ENGLISH);
        if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
            throw new MethodNotSupportedException(method + " method not supported"); 
        }
        String target = readResourceURI(request);
        
        final File file = new File(ServerConfig.getInstance().getProperties().getBase( ),
        		URLDecoder.decode(target, "UTF-8"));
        String mimeType = "text/html; charset=UTF-8";
        if ( !file.isDirectory()) {
        	Pattern pattern = Pattern.compile( "(.*\\.)(\\S+)");
        	Matcher matcher = pattern.matcher( file.getName( ));

        	if ( matcher.find( )) {
        		Map<String, String> mimeTypes = ServerConfig.getInstance().getProperties().getMimeTypes();
        		if ( matcher.group(2) != null && mimeTypes.get( matcher.group(2)) != null)
        			mimeType = mimeTypes.get( matcher.group(2));
        		else {
        			response.setStatusCode( HttpStatus.SC_NOT_ACCEPTABLE);
        			response.setEntity( new EntityTemplate(new UnsupportedFileExtension())) ;
        			log.info( "Mime type for file extension " + matcher.group(2) + " is not defined. Using the default one.");
        			return;
        		}
        	} else {
        		log.info( "File +" + file.getName( ) + " doesn't have recognizable file extension. Using default mime type.");
        		response.setStatusCode( HttpStatus.SC_NOT_ACCEPTABLE);
        		response.setEntity( new EntityTemplate(new UnsupportedFileExtension())) ;
        		return;
        	}
        }
        
        if (request instanceof HttpEntityEnclosingRequest) {
            HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
            byte[] entityContent = EntityUtils.toByteArray(entity);
           log.info("Incoming entity content (bytes): " + entityContent.length);
        }
        
        File requestedFile = null;
        if ( file.isDirectory( )) {
        	String[] list = file.list();
        	for ( String $ : list) {
        		if ( ServerConfig.getInstance().getProperties().getWelcomeFiles( ).contains( $))
        			requestedFile = new File( file, $);
        	}
        } 
        if ( requestedFile == null)
        	requestedFile = file;
        
        if (!requestedFile.exists()) {
            response.setStatusCode(HttpStatus.SC_NOT_FOUND);
            EntityTemplate body = new EntityTemplate( new FileNotFoundContenProducer());
            body.setContentType("text/html; charset=UTF-8");
            response.setEntity(body);
            log.info( "File " + requestedFile.getPath() + " not found");
        } else if (!requestedFile.canRead() || requestedFile.isDirectory( )) {
            response.setStatusCode(HttpStatus.SC_FORBIDDEN);
            EntityTemplate body = new EntityTemplate(new AccessDeniedContentProducer( ));
            body.setContentType("text/html; charset=UTF-8");
            response.setEntity(body);
            log.info( "Cannot read file " + requestedFile.getPath());
        } else {
            response.setStatusCode(HttpStatus.SC_OK);
            FileEntity body = new FileEntity(requestedFile, mimeType);
            response.setEntity(body);
            log.info("Serving file " + requestedFile.getPath());
        }
	}
	
	private String readResourceURI(HttpRequest request) {
		String uri = request.getRequestLine().getUri( );
		String host = "";
		if ( request.getHeaders( HTTP.TARGET_HOST) != null) {
			host = request.getHeaders( HTTP.TARGET_HOST)[0].getValue( );
		}
		if ( !uri.contains(host))
			return uri;
		return uri.substring( uri.indexOf(host) + host.length( ), uri.length( ));
	}
}
